package com.zsl.swing.redis.desktop.window.panel;

import com.zsl.swing.redis.desktop.model.FontSizeConfigEntity;
import com.zsl.swing.redis.desktop.type.OtherMenuEnum;
import com.zsl.swing.redis.desktop.utils.FontUtils;
import com.zsl.swing.redis.desktop.utils.StringUtils;
import com.zsl.swing.redis.desktop.window.ZslRedisDesktopMainWindow;
import com.zsl.swing.redis.desktop.window.menu.ZslMenuItem;

import javax.swing.*;
import javax.swing.text.Document;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;

/**
 * 日志面版
 */
public class ZslLogPanel extends JScrollPane  implements ActionListener {

    /**
     * 日志记录文本域
     */
    private final JTextArea logArea = new JTextArea(10, 50);

    private static final String LOG_FORMAT = "ZslRedisDesktop:%s:%s>%s";

    private static final String ERROR_LEVEL = "ERROR";
    private static final String INFO__LEVEL = "INFO ";

    private static final int LOG_ROWS_LIMIT = 100;

    public ZslLogPanel(){
        super();

        this.setViewportView(this.logArea);

        this.logArea.setBorder(BorderFactory.createTitledBorder("日志"));

        this.logArea.setEditable(false);
        this.logArea.setLineWrap(false);

        FontSizeConfigEntity fontSizeConfig = ZslRedisDesktopMainWindow.getFontSizeConfig();
        this.logArea.setFont(FontUtils.getFont(fontSizeConfig.getFontName(), Font.PLAIN, fontSizeConfig.getLogArea()));
        this.logArea.addMouseListener(this.buildMouseAdapter());

    }

    private MouseAdapter buildMouseAdapter(){
        return new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                int button = e.getButton();
                if(MouseEvent.BUTTON3 == button){

                    ZslMenuItem copyItem = ZslMenuItem.getInstance(OtherMenuEnum.COPY.getText(), ZslLogPanel.this);
                    ZslMenuItem cleaItem = ZslMenuItem.getInstance(OtherMenuEnum.CLEAR.getText(), ZslLogPanel.this);
                    JPopupMenu popupMenu = new JPopupMenu();
                    popupMenu.add(copyItem);
                    popupMenu.add(cleaItem);

                    String errorLog = ZslLogPanel.this.logArea.getText();
                    if(StringUtils.isEmpty(errorLog)){
                        cleaItem.setEnabled(false);
                        copyItem.setEnabled(false);
                    }

                    popupMenu.show(ZslLogPanel.this.logArea,e.getX(),e.getY());
                }

            }
        };
    }


    @Override
    public void actionPerformed(ActionEvent e) {
        String command = e.getActionCommand();
        if(OtherMenuEnum.CLEAR.getText().equals(command)){
            this.logArea.setText(null);
            return;
        }

        String selectedText = this.logArea.getSelectedText();
        if(!StringUtils.isEmpty(selectedText) && OtherMenuEnum.COPY.getText().equals(command)){
            this.logArea.copy();
        }
    }

    private String currentTime(){
        String format = "yyyy-MM-dd mm:hh:ss.SSS";
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(format));
    }

    private String buildErrorMsg(Object msg){
        return String.format(LOG_FORMAT,ERROR_LEVEL,this.currentTime(),msg);
    }

    private String buildMsg(Object msg){
        return String.format(LOG_FORMAT,INFO__LEVEL,this.currentTime(),msg);
    }

    public synchronized void logError(Throwable e) {

        this.checkAndHandleRowsLimit();

        StringWriter stringWriter = new StringWriter();
        e.printStackTrace(new PrintWriter(stringWriter));

        this.logArea.append(this.buildErrorMsg(stringWriter));
        this.logArea.append("\n");
        this.logArea.paintImmediately(this.logArea.getBounds());
    }

    private synchronized void checkAndHandleRowsLimit(){
        String[] splits = this.logArea.getText().split("\n");

        int length = splits.length;
        if(length >= LOG_ROWS_LIMIT){

            StringBuilder sb = new StringBuilder();
            for(int i = length - 20; i< length; i++){
                sb.append(splits[i]).append("\n");
            }

            this.logArea.setText(sb.toString());
        }
    }

    public synchronized void logError(String msg){
        this.checkAndHandleRowsLimit();

        this.logArea.append(this.buildErrorMsg(msg));
        this.logArea.append("\n");
        this.logArea.paintImmediately(this.logArea.getBounds());
    }
    public synchronized void log(String msg){
        this.checkAndHandleRowsLimit();

        this.logArea.append(this.buildMsg(msg));
        this.logArea.append("\n");
        this.logArea.paintImmediately(this.logArea.getBounds());
    }

}
